------------------------------------------- -- Helper for (dynamic_news_manager.script) -- Last edit by Tronex (2018/6/25) --========================================= --=================================================< Tables >================================================= level_points = { ["jupiter"] = { { -349.75, 3.9878, 407.8909}, --the Ash Heap anomaly { -161.104, 3.594, 390.616}, --the tower { 73.6377, 4.6632, 324.0991}, --the substation { 228.0958, -4.8275, 404.7565}, --the Plavni anomaly { 356.3688, 33.4261, 335.5996}, --the cement factory { -341.2063, -3.9061, 235.3816}, --Kopachi { -51.0059, 3.4884, 199.2509}, --Yanov { 276.5087, -29.4639, 163.2693}, --the quarry { -196.3071, -3.748, 72.5475}, --the mobile lab { -360.9959, 11.2529, -6.6707}, --the Volkhov complex { 55.7362, 10.5284, -18.2494}, --the anomalous grove { -108.4109, -0.3887, -145.4128}, --the parking lot { 43.5119, 23.9638, -190.6825}, --the checkpoint { 213.3307, 0.5969, -70.0109}, --the Bitumen anomaly { 399.7508, 4.505, -103.8042}, --the eastern tunnel { -412.9768, -0.0092, -343.6718}, --the storage containers { -65.5894, 23.7972, -322.6659}, --the ventilation complex { -128.901, 26.8013, -470.7353}, --the helipad { 234.1494, 15.171, -316.6919}, --the Concrete Bath anomaly { 277.403, 27.6236, -231.8324} --the Jupiter factory }, ["jupiter_underground"] = { { 0, 0, 0} --the tunnels }, ["k00_marsh"] = { { -161.21,0.39,-299.14}, --the Clear Sky base { 37.51, 5.32, -228.54}, --the fishery { -6.08,11.19,19.42}, --the pump station { -254.83, 2.19, -110.17}, --the anomaly cluster { 165.38, 12.61, 535.36}, --the road to Agroprom { 417.38, 5.32, 236.78}, --the machine yard { 280.52, 5.5, 61.02}, --the burnt house { 486.19, 4.36, -175.46}, --the southern checkpoint { 285.02, 1.8, -160.7} --the old church }, ["k01_darkscape"] = { { -587.87, -0.1, -411.62}, --the road to Cordon { 427.23, -0.12, -362.48}, --the gas station { 255.27, 1.14, -189.09}, --the sawmill { 400.78, -1.3, 285.05}, --the bridge { -405.64, 2.82, 623.14} --the road to Dark Valley }, ["k02_trucks_cemetery"] = { { -216.822, 6.515, 139.917}, --the way to Rostok { 85.541, 4.834, 62.382}, --the helicopters { 87.56, 6.566, 203.66}, --the fire trucks { -39.466, 10.116, 340.233}, --the radioactive hills { 219.7, 7.659, 304.56}, --the north eastern checkpoint { -10.543, 24.334, -88.519}, --the hill in the woods { -139.04, 1.867, -37.843}, --the valley { -91.354, 6.6, -299.094}, --the containers { 50.707, 13.272, -371.74} --the southern parking lot }, ["l01_escape"] = { { -156.24, -28.86, -344.82}, --the southern checkpoint { -190.0, -18.32, -147.271}, --the rookie village { -215.8, -7.9, -39.57}, --the trash pit { 86.19, -6.59, -16.25}, --the car park { 58.5, 3.05, 135.78}, --the railway embankment { 18.44, 2.03, 277.14}, --the farm { 104.92, 2.94, 510.45}, --the anomaly in the woods { 319.45, 13.92, 219.38}, --the train tunnel { 17.83, 17.45, 661.86} --the northern checkpoint }, ["l02_garbage"] = { { 37.24, 2.14, 225.37}, --the Rostok checkpoint { -213.44, 0.43, 105.17}, --the Synapse anomaly { -112.15, 2.02, 10.16}, --the Depot { -77.65, -0.95, -211.41}, --the vehicle graveyard { 94.49, 1.75, -143.77}, --the swamp { 94.77, -1.31, -257.22}, --the anomaly by the road { 36.25, 2.13, -303.03} --the road to Cordon }, ["l03_agroprom"] = { { 160.72, 9.81, 96.51}, --the anomaly on the hill { 26.26, 1.46, -6.7}, --the northern complex { 12.68, 0.13, -256.75}, --the anomaly to the south { -126.75, 1.45, -183.51}, --the southern complex { -194.71, 1.23, -41.46}, --the Bedrock Claws anomaly { -214.78, 3.58, 58.75} --the swamps }, ["l04_darkvalley"] = { { -112.69, 2.3, -485.54}, --the abandoned farm { 91.62, 3.32, -481.87}, --the Glowing Pit anomaly { 134.25, 2.23, -309.97}, --the moving fireball { 7.68, 1.45, -102.67}, --the factory { 112.59, 1.7, -66.32}, --the gas station { 30.21, 1.66, 14.56}, --the bandit base { -146.82, 2.39, -196.14} --the exit to the Garbage }, ["l05_bar"] = { { 89.2, 1.65, 139.18}, --the western checkpoint { 130.31, 1.8, 47.0}, --the entrance to the bar { 205.14, 1.61, 96.77}, --the Duty base { 37.67, -1.41, 301.72} --the road to the Army Warehouses }, ["l06_rostok"] = { { -83.34, -14.13, -218.59}, --the road to Yantar { -158.44, -4.35, -87.61}, --the burning tunnel { -236.53, 1.65, 53.01}, --the construction site { -30.32, 1.66, 144.36}, --the parking lot { 31.64, 1.04, 139.91} --the road to Rostok }, ["l07_military"] = { { -304.69, -20.42, 49.06}, --the old farmstead { -182.28, -7.18, 20.62}, --the anomaly on the southern hill { -7.5, -4.53, 33.44}, --the Freedom base { 54.76, -9.58, 125.94}, --the old shack { -289.24, -21.03, 237.12}, --the abandoned village { -15.75, -1.53, 438.12}, --the road to Dead City { -198.25, -2.75, 419.77} --the road to Radar }, ["l08_yantar"] = { { -16.3, -10.83, -243.71}, --the anomaly behind the plant { 31.51, -10.08, -272.61}, --the mobile lab { -169.33, 4.7, -157.45}, --the plant { 102.32, 1.6, -39.23}, --the entrance to the plant { -21.81, 2.15, 3.46} --the road to Dead City }, ["l09_deadcity"] = { { 154.53, -1.47, -24.22}, --the tunnel to the Army Warehouses { -9.47, 1.92, -201.1}, --the road to Yantar { -39.93, 3.39, 31.96}, --the mercenary base { -59.58, 2.74, 96.5}, --the road to Limansk { -47, 3.15, -71.93}, --the derelict monoblock { 40.27, 2, -90.69}, --the abandoned school { -142.33,1.12,-99.62} --the isolated houses }, ["l10_limansk"] = { { -46.64, -3.35, -239.41}, --the road to Dead City { 4.1, 1.65, -359.17}, --the tunnel to Red Forest { 63.81, 4.16, 298.25}, --the radiowave institute { 13.18, 13.51, 184.49}, --the construction site { 25, -3, 37.68}, --the bridge outpost { -52.55, -4.53, -151.69}, --the gastronom }, ["l10_radar"] = { { 12.27, 1.36, -64.97}, --the antennas { 384.88, -32.47, 140.24}, --the road to Pripyat { 593.76, -51.30, -356}, --the road to Army Warehouses { 447.60, -50, 8.86}, --the road block { 438.43, -55.63, -150.77} --the forest }, ["l10_red_forest"] = { { -119.31, 1.78, -270.63}, --the bridge { -2.74, -1.55, -231.93}, --the Superconductor anomaly { 208.88, -4.89, -107.13}, --the tunnel camp { 124.43, 1.79, -271.92}, --the road to Radar { -85.2, 3.93, -56.17}, --the open field { -56.6, 2.05, -31.23} --the road to Jupiter }, ["l11_pripyat"] = { { 4.03, -0.04, -256.47}, --the road to Radar { 6.42, 1.65, 159.31} --the Monolith base }, ["labx8"] = { { 0, 0, 0} --the lab }, ["pripyat"] = { { 81.8565, -16.6709, -1054.051}, --the Prometheus theater { 293.7553, 0.6782, 231.0446}, --the river port { 11.1927, 4.4952, 277.1345}, --the old KBO { 56.3268, 1.6092, 127.6943}, --the school { 222.1708, -0.2035, 32.2432}, --the hospital { -59.2026, 8.6021, 94.3039}, --KBO Jubilee { 154.753, -0.0955, -185.3917}, --the laundromat { -109.6032, 4.1258, -105.4647}, --the playground { 46.9189, 16.5275, -139.9859}, --the dormitory { -198.7285, -0.1768, -199.4987}, --the grocery store { -101.6807, 0.5108, -257.1676}, --the department store { -181.141, 0.5491, -347.6817}, --the book store { -177.9315, -0.5841, -30.081}, --the Volcano anomaly { 154.266, 0.0355, 216.7533} --the Vine anomaly }, ["zaton"] = { { -33.0228, 0.4555, -200.7156}, --the Claw anomaly { -355.6813, 40.0176, -325.4126}, --the Iron Forest anomaly { -349.0496, 18.3864, 345.0177}, --the sawmill { -400.3414, 6.4376, -9.3092}, --the antenna complex { 321.9968, 33.2427, -403.7212}, --the waste processing plant { 0.5964, 20.9242, -332.0877}, --the Circus anomaly { 420.0504, 36.2633, -17.5632}, --the ranger station { 132.5715, -7.3392, 185.0458}, --Skadovsk { -48.5605, 24.1285, 303.5849}, --the burnt village { 421.4176, -4.357, 413.4552}, --the Boiler anomaly { -355.5159, 7.6103, 250.3168}, --the swamp { -173.2566, 7.7176, 99.8053}, --Izumrudnoye { 11.8022, -5.1532, 35.2991}, --Shevchenko { 394.4182, -5.8341, 228.9845}, --the dredge station { 212.8967, 6.8029, 14.0857}, --the dock cranes { -283.9678, 21.0929, -136.5675}, --the Oakpine anomaly { -103.5785, -5.4548, -220.5178}, --the refuelling station { 152.5881, -6.8237, -139.0262}, --the old barge { 323.3748, -5.2372, -219.5806}, --the Scar anomaly { 429.9237, 20.2642, -182.6681}, --Preobrazhensky bridge { 77.0241, 39.0102, -478.4914}, --the southern plateau { -135.3534, 24.5687, -412.9718} --the workshop substation }, ["y04_pole"]={ {-138.68,-19.67,-39.56}, {-106.68,0.27,73.55}, {-124.15,-0.20,166.70}, {42.66,0.00,142.58} } } local invalid_maps = { -- dynamic news are off in those maps "jupiter_underground", "l08u_brainlab", "l04u_labx18", "l10u_bunker", "labx8", "l12u_sarcofag", "l12u_control_monolith", "l13u_warlab", "l13_generators" } local all_direction = {"near","east","north_east","north","north_west","west","south_west","south","south_east"} --=================================================< Helpers >================================================= local function PickRandomKey(t,is_key) -- Selects a random item from a table local keys = {} for key, value in pairs(v) do keys[#keys+1] = key -- Store keys in another table end index = keys[math.random(1, #keys)] if is_key then return index else return t[index] end end local function get_object_levelname(obj) if not (obj) then return "nil" end local gvid = obj.m_game_vertex_id or obj.game_vertex_id and obj:game_vertex_id() if not (gvid) then return "nil" end local gg = game_graph() if (gg:valid_vertex_id(gvid)) then cvertex = gg:vertex(gvid) return alife():level_name(cvertex:level_id()) end return "nil" end --=================================================< Pickers >================================================= function GetPointDescription(obj) local level_name = get_object_levelname(obj) if not (level_name) then return end local m_s = game.translate_string("st_dyn_news_"..level_name) local point = type(obj.position) == "function" and obj:position() or obj.position if not (point) then return m_s end local points = level_points[level_name] if not (points) then return m_s end local m_point = nil local near_id = nil local near_dist = nil for i=1,#points do local value = points[i] local pos = vector():set(value[1],value[2],value[3]) local dist = pos:distance_to_sqr(point) if (near_dist == nil or dist < near_dist) then near_dist = dist near_id = i near_point = pos end if (near_dist <= 30) then -- pointless to process further break end end if not (near_point) then return m_s end local m_str = game.translate_string("st_dyn_"..level_name.."_daleko_"..near_id) local m_str0 = game.translate_string("st_dyn_"..level_name.."_blizko_"..near_id) if near_dist <= 20 then return strformat("%s %s",m_s,m_str0) elseif near_dist < 50 then return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_near"),m_str) elseif near_dist < 100 then return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_close"),m_str) end local dx = point.x-near_point.x local dy = point.z-near_point.z local radians = math.atan2(dy,dx) local angle = 0 if (radians) then angle=radians*57 if(angle < 0)then angle = angle+360 end if(angle > 360)then angle = angle-360 end end if (angle>=330 or angle<=30) then return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_east"),m_str) elseif (angle>30 and angle<=60) then return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_north_east"),m_str) elseif (angle>60 and angle<=120) then return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_north"),m_str) elseif (angle>120 and angle<=150) then return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_north_west"),m_str) elseif (angle>150 and angle<=210) then return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_west"),m_str) elseif (angle>210 and angle<=240) then return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_south_west"),m_str) elseif (angle>240 and angle<= 300) then return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_south"),m_str) elseif (angle>300 and angle<=330) then return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_south_east"),m_str) end return strformat("%s %s %s",m_s,game.translate_string("st_dyn_news_close"),m_str) end function GetTimeString(TimeDiffHrs,AccuracyTier) -- convert the difference between current and event time into a proper string - INPUT: time difference (hours), Accuracy Tier (1 to 6) - OUTPUT: string -- Preparing variables if TimeDiffHrs <= 1 then return false end local TimeNext = game.get_game_time() local Y, M, D, h, m, s, ms = 0, 0, 0, 0, 0, 0, 0 Y, M, D, h, m, s, ms = TimeNext:get(Y, M, D, h, m, s, ms) TimeNext:set(Y, M, D, h + TimeDiffHrs, m, s, ms) local TimeStringRange, TimeStringNumber, TimeStringPharse local hrs = GetTimeScope(TimeNext,4) -- hour of event local s_p = "" -- adding the plural "s" local endString = "" -- Little touch for ending part local dayPart = "" -- PM or AM local result -- Best time accuracy (Tier 6), short time range (1 day), example: "at 8 PM" if AccuracyTier == 6 and IsDateCloseBy(TimeNext,3,0) then if hrs > 12 then hrs = hrs - 12 dayPart = game.translate_string("st_dyn_news_day_part_pm") else dayPart = game.translate_string("st_dyn_news_day_part_am") end result = strformat("%s %s %s",game.translate_string("st_dyn_news_at"),tostring(hrs),dayPart) -- Good time accuracy (Tier 5), short time range (1 day), example: "between 3:00 and 5:00" elseif AccuracyTier == 5 and IsDateCloseBy(TimeNext,3,0) then local hrs_R, hrs_L local hrs_parts = {} for i = 1,5 do -- range (hrs - 2) to (hrs + 2) hrs_parts[i] = math.floor(hrs + (i-3)) if hrs_parts[i] >= 24 then hrs_parts[i] = math.floor(hrs_parts[i] - 24) -- if the hour exceeds 24, correct it. elseif hrs_parts[i] < 0 then hrs_parts[i] = math.floor(hrs_parts[i] + 24) end -- if the hour is negative number, correct it. end if hrs_parts[1] <= GetTimeScope(game.get_game_time(),4) then return false end -- if the current hour is within the time range, return if math.random(2) == 1 then hrs_L = hrs_parts[1] else hrs_L = hrs_parts[2] end if math.random(2) == 1 then hrs_R = hrs_parts[4] else hrs_L = hrs_parts[5] end if hrs_R and hrs_L then result = strformat("%s %s:00 %s %s:00",game.translate_string("st_dyn_news_between"),tostring(hrs_L),game.translate_string("st_dyn_news_and"),tostring(hrs_R)) end -- Good time accuracy (Tier 4), huge time range (1 year), example: "in three hours" elseif AccuracyTier == 4 and IsDateCloseBy(TimeNext,1,0) then local h = TimeDiffHrs local d = math.floor(h/24) local m = math.floor(h/(24*30)) if h > 0 and h < 24 then -- hours range TimeStringRange = game.translate_string("st_dyn_news_hour") TimeStringNumber = game.translate_string("st_dyn_news_number_" .. tostring(h)) if h > 1 then s_p = game.translate_string("st_dyn_news_s_p") end elseif h >= 24 and d > 0 and d <= 30 then -- days range TimeStringRange = game.translate_string("st_dyn_news_day") TimeStringNumber = game.translate_string("st_dyn_news_number_" .. tostring(d)) if d > 1 then s_p = game.translate_string("st_dyn_news_s_p") end elseif d > 30 and m > 0 and m <= 12 then -- month range TimeStringRange = game.translate_string("st_dyn_news_month") TimeStringNumber = game.translate_string("st_dyn_news_number_" .. tostring(m)) if m > 1 then s_p = game.translate_string("st_dyn_news_s_p") end end local l, str l = math.random(3) if l == 1 then str = game.translate_string("st_dyn_news_in") elseif l == 2 then str = game.translate_string("st_dyn_news_within") elseif l == 3 then str = strformat("%s %s",game.translate_string("st_dyn_news_in"),game.translate_string("st_dyn_news_about")) end if math.random(2) == 1 then endString = strformat(" %s %s",game.translate_string("st_dyn_news_or"),game.translate_string("st_dyn_news_so")) end if TimeStringNumber and TimeStringRange then result = strformat("%s %s %s%s %s",str,TimeStringNumber,TimeStringRange,s_p,endString) end -- Average time accuracy (Tier 3), good time range (2 days), example: "this morning" elseif AccuracyTier == 3 and IsDateCloseBy(TimeNext,3,1) then if (GetTimeScope(TimeNext,3) == GetTimeScope(game.get_game_time(),3)) then TimeStringRange = game.translate_string("st_dyn_news_this") elseif (GetTimeScope(TimeNext,3) == GetTimeScope(game.get_game_time(),3) + 1) then TimeStringRange = game.translate_string("st_dyn_news_tomorrow") end if hrs >= 21 or hrs < 4 then TimeStringPharse = game.translate_string("st_dyn_news_night") end if hrs >= 4 and hrs < 8 then TimeStringPharse = game.translate_string("st_dyn_news_morning") end if hrs >= 8 and hrs < 11 then TimeStringPharse = game.translate_string("st_dyn_news_noon") end if hrs >= 11 and hrs < 15 then TimeStringPharse = game.translate_string("st_dyn_news_afternoon") end if hrs >= 15 and hrs < 21 then TimeStringPharse = game.translate_string("st_dyn_news_evening") end if TimeStringRange and TimeStringPharse then result = strformat("%s %s",TimeStringRange,TimeStringPharse) end -- Bad time accuracy (Tier 2), good time range (about a week), example: "today" elseif AccuracyTier == 2 and IsDateCloseBy(TimeNext,3,6) then if (GetTimeScope(TimeNext,3) == GetTimeScope(game.get_game_time(),3)) then TimeStringRange = game.translate_string("st_dyn_news_today") elseif (GetTimeScope(TimeNext,3) == GetTimeScope(game.get_game_time(),3) + 1) then TimeStringRange = game.translate_string("st_dyn_news_tomorrow") elseif (GetTimeScope(TimeNext,3) > GetTimeScope(game.get_game_time(),3) + 1) and (GetTimeScope(TimeNext,3) < GetTimeScope(game.get_game_time(),3) + 6) then TimeStringRange = game.translate_string("st_dyn_news_few_days") end if TimeStringRange then result = TimeStringRange end -- Bad time accuracy (Tier 1), good time range (about few day), no need for scope check, example: "soon" elseif AccuracyTier == 1 and IsDateCloseBy(TimeNext,3,3) then if (GetTimeScope(TimeNext,3) == GetTimeScope(game.get_game_time(),3)) then TimeStringRange = strformat("%s %s",game.translate_string("st_dyn_news_very") , game.translate_string("st_dyn_news_soon")) elseif (GetTimeScope(TimeNext,3) > GetTimeScope(game.get_game_time(),3)) and (GetTimeScope(TimeNext,3) <= GetTimeScope(game.get_game_time(),3) + 3) then TimeStringRange = game.translate_string("st_dyn_news_soon") end if TimeStringRange then result = TimeStringRange end end if result then return result else -- if we got no result, use the biggest time range return GetTimeString(TimeDiffHrs, 4) end end function GetTimePharseAsString() -- return a string represent the current time pharse local hrs = GetTimeScope(game.get_game_time(),4) if hrs >= 21 or hrs < 4 then TimeStringPharse = "night" end if hrs >= 4 and hrs < 8 then TimeStringPharse = "morning" end if hrs >= 8 and hrs < 15 then TimeStringPharse = "noon" end if hrs >= 15 and hrs < 21 then TimeStringPharse = "evening" end return TimeStringPharse end function GetTimeScope(EventDate,scope) -- Take input as a (date, time scope), return current in-game time for related scope, Example: GetTimeScope(game.get_game_time(), 4) will return the current hour local Y, M, D, h, mint, sec, ms = EventDate:get() local tbl = {Y, M, D, h, mint, sec, ms} return tbl[scope] end function IsDateCloseBy(EventDate,scope,count) -- return true if the event date is under time range specified by scope (time unit) and count (how much difference) local TimeThen = GetTimeScope(EventDate, scope) local TimeNow = GetTimeScope(game.get_game_time(), scope) if TimeThen <= TimeNow + count then return true else return false end end function PickFaction(only_natural) -- pick a random faction local tbl = {} for key, value in pairs(faction_expansions.faction) do if (only_natural == nil) or ((only_natural == true) and (not game_relations.is_factions_enemies(get_actor_true_community(),key))) or (only_natural ~= true) then tbl[#tbl+1] = key end end return tbl[math.random(#tbl)] end function GetFaction(key1,key2) if key1 and (not faction_expansions.faction[key1]) then return nil end if key2 and (type(key2) == "string") then return faction_expansions.faction[key1][key2] end return faction_expansions.faction[key1] end function PickMap(excluded_map) local tbl = {} for key, value in pairs(faction_expansions.level) do if (excluded_map == nil) or (excluded_map and key ~= excluded_map) then tbl[#tbl+1] = key end end return tbl[math.random(#tbl)] end function PickMutant(tier) local tbl = {} for key, value in pairs(faction_expansions.mutant) do if (tier == nil) or (tier and key["tier"] == tier) then tbl[#tbl+1] = key end end return tbl[math.random(#tbl)] end function GetMutant(key1,key2) if key2 and (type(key2) == "string") then return faction_expansions.mutant[key1][key2] end return faction_expansions.mutant[key1] end function PickDirection() local pick = all_direction[math.random(#all_direction)] local pick_str = game.translate_string("st_dyn_news_" .. pick) if pick_str == ("st_dyn_news_" .. pick) then return "near" end return pick_str end function IsInvalidMap(map) for i=1,#invalid_maps do if (map == invalid_maps[i]) then return true end end return false end function list_actor_squad_by_id() -- This is the same function used in axr_companions in CoC 1.5, brought here to be used in all CoC variants. local t = {} local size_t = 0 for id,squad in spairs(axr_companions.companion_squads, function(t,a,b) return a < b end) do if (squad and squad.commander_id) then if (not axr_task_manager.hostages_by_id[squad:commander_id()]) and (not axr_task_manager.hostages_by_id[squad:commander_id()]) then for k in squad:squad_members() do --printf("member %s",k.id) size_t = size_t + 1 t[size_t] = k.id end end end end return t end function GetCommunityDescription(obj,index) -- Return the faction of the sender (obj) local comm = obj:character_community() if (obj:id() == AC_ID and comm ~= "actor") then comm = comm:sub(7) end if (not comm) then callstack() -- debug due to related crash with unknown obj return "unknown" --"some asshole" end local msg = game.translate_string("st_dyn_news_comm_" .. comm .. "_" .. index) if (msg == "st_dyn_news_comm_" .. comm .. "_" .. index) then return "unknown" --"some asshole" end return msg end function GetMonsterDescription(obj,index,sec,cls) -- Get monster description, return translation local sec = obj and obj:section() or sec local cls = obj and obj:clsid() or cls local kind = sec and ini_sys:r_string_ex(sec,"kind") or "NA" if sec and index then local msg = game.translate_string("st_dyn_news_" .. sec .. "_" .. index) if (msg == "st_dyn_news_" .. sec .. "_" .. index) then msg = nil end if msg then return msg elseif not (IsMonster(nil,cls)) then if sec:find("_zombied") then return game.translate_string("st_dyn_news_zombied_" .. index) else return "not a monster" end end end local m_class = { [clsid.bloodsucker_s] = "bloodsucker", [clsid.boar_s] = "boar", [clsid.burer_s] = "burer", [clsid.cat_s] = "cat", [clsid.chimera_s] = "chimera", [clsid.controller_s] = "controller", [clsid.dog_s] = "dog", [clsid.flesh_s] = "flesh", [clsid.fracture_s] = "fracture", [clsid.gigant_s] = "gigant", [clsid.poltergeist_s] = "poltergeist", [clsid.pseudodog_s] = "pseudodog", [clsid.psy_dog_phantom_s] = "psy_dog_phantom", [clsid.psy_dog_s] = "psy_dog", [clsid.rat_s] = "rat", [clsid.snork_s] = "snork", [clsid.tushkano_s] = "tushkano", [clsid.zombie_s] = "zombie" } local m_section = { ["SM_KARLIK"] = "karlik", ["SM_PSYSUCKER"] = "psysucker", ["SM_LURKER"] = "lurker" } if clsid.karlik_s then m_class[clsid.karlik_s] = "karlik" end --> CoC 1.5 if clsid.psysucker_s then m_class[clsid.psysucker_s] = "psysucker" end --> A-Life Revamp if clsid.lurker_s then m_class[clsid.lurker_s] = "lurker" end --> A-Life Revamp if (not index) then return m_section[kind] or m_class[cls] end return game.translate_string("st_dyn_news_" .. (m_section[kind] or m_class[cls]) .. "_" .. index) or "" end function GetWeaponClass(obj) local wpn = obj:active_item() if not (wpn) then return 1 end local cls = wpn:clsid() if (IsRifle(nil,cls)) then return wpn:weapon_is_silencer() and 9 or 2 elseif (IsPistol(nil,cls)) then return wpn:weapon_is_silencer() and 9 or 3 elseif (IsSniper(nil,cls)) then return wpn:weapon_is_silencer() and 9 or 4 elseif (IsShotgun(nil,cls)) then return 5 elseif (cls == clsid.wpn_knife_s) then return 6 elseif (IsLauncher(nil,cls)) then return 7 elseif (cls == clsid.wpn_grenade_f1_s or cls == clsid.wpn_grenade_rgd5_s) then return 8 end return 1 end function GetWeaponDescription(obj,index) local cls = GetWeaponClass(obj) return game.translate_string("st_dyn_news_wpn_cls_"..cls.."_"..index) end function GetColor(num) local clr = all_colors[num] if clr then return clr else return "" end end --------------------------------------------------------------------------------- function send_tip(msg, header, timeout, showtime, sender, sound, icon_by) -- Send news if not (msg and db.actor) then -- if (actor is dead) and (there is not message) return false end msg = "%c[default]" .. game.translate_string(msg) header = header or game.translate_string("st_tip") -- sender name timeout = timeout or 0 showtime = showtime or 7 sender = sender or "default" -- faction -- sound effect depends on the type of news local function news_snd(snd) if snd =="news" then xr_sound.set_sound_play(AC_ID, "pda_tips") elseif snd == "danger" then xr_sound.set_sound_play(AC_ID, "pda_alarm") elseif snd == "communication_lost" then xr_sound.set_sound_play(AC_ID, "pda_communication_lost") elseif snd == "beep_1" then xr_sound.set_sound_play(AC_ID, "pda_beep_1") elseif snd == "beep_2" then xr_sound.set_sound_play(AC_ID, "pda_beep_2") elseif snd == "welcome" then xr_sound.set_sound_play(AC_ID, "pda_welcome") elseif snd == nil then xr_sound.set_sound_play(AC_ID, "pda_tips") end return true end if (timeout == 0) then news_snd(sound) else CreateTimeEvent("dynamic_news_snd_delay", math.random(1000), timeout, news_snd, sound) end -- pick icon to show if icon_by=="gr" then ui_sender = news_manager.tips_icons[sender] elseif icon_by=="npc" then ui_sender = sender elseif icon_by==nil then ui_sender = news_manager.tips_icons[sender] end -- if icon is nil if not (ui_sender) then return false end -- consume PDA power item_device.drain_device_on_event(db.actor:item_in_slot(8), nil, 1) -- send the news db.actor:give_game_news(header, msg, ui_sender, timeout*1000, showtime*1000) return true end